﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml;
using System.Text.RegularExpressions;
using System.Text;

namespace RSSFunnel
{
    public partial class _default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            GetRss();
        }

        private void GetRss()
        {
            Response.Clear();
            Response.ContentType = "text/xml";

            var xml = new XmlDocument();
            xml.Load(Server.MapPath("~/App_Data/RSSFunnel.xml"));
            var sources = xml.DocumentElement.SelectNodes("Rss");

            var filteredItems = new List<XmlNode>();
            foreach (XmlNode source in sources)
            {
                var url = source.Attributes["Url"].Value;
                var xmlRss = new XmlDocument();
                xmlRss.Load(url);

                var items = xmlRss.DocumentElement.SelectNodes("//item");
                var rules = source["Rules"].SelectNodes("Rule");

                var blockledItems = new List<string>();
                var allowedItems = new List<string>();
                foreach (XmlNode rule in rules)
                {
                    var action = rule.Attributes["Action"].Value.Trim();
                    var op = rule.Attributes["Operator"].Value.Trim();

                    var fields = rule.SelectNodes("Field");
                    foreach (XmlNode item in items)
                    {
                        var conditions = new bool[fields.Count];

                        for (int i = 0; i < fields.Count; i++)
                        { // loop on fields
                            var fieldNode = fields[i];
                            var field = fieldNode.Attributes["Name"].Value;
                            var filter = fieldNode.Attributes["Filter"].Value;
                            var what = fieldNode.Attributes["What"].Value;

                            var searchText = "";
                            if (field == "*") searchText = Regex.Replace(item.InnerXml.Replace("&gt;", ">").Replace("&lt;", "<"), "<[^>]*>", "");
                            else if (item[field] != null) searchText = item[field].InnerText;

                            var comparer = StringComparer.OrdinalIgnoreCase;
                            var condition = false;
                            switch (filter)
                            {
                                case "eq": // equals
                                    condition = comparer.Equals(searchText, what);
                                    break;

                                case "nq": // not-equals
                                    condition = !comparer.Equals(searchText, what);
                                    break;

                                case "cn": // contains
                                    condition = searchText.IndexOf(what, StringComparison.OrdinalIgnoreCase) >= 0;
                                    break;

                                case "nc": // not-contains
                                    condition = searchText.IndexOf(what, StringComparison.OrdinalIgnoreCase) < 0;
                                    break;
                            }

                            conditions[i] = condition;
                        }

                        var isTrue = IsTrue(conditions, op);
                        var guid = item["guid"].InnerText;
                        if (action == "block" && isTrue && !blockledItems.Contains(guid)) blockledItems.Add(guid); // want block and true
                        else if (action == "block" && !isTrue && !allowedItems.Contains(guid)) allowedItems.Add(guid); // want block and false
                        else if (action == "allow" && isTrue && !allowedItems.Contains(guid)) allowedItems.Add(guid); // want allow and true
                        else if (action == "allow" && !isTrue && !blockledItems.Contains(guid)) blockledItems.Add(guid); // want allow and false
                    }
                }

                foreach (var item in blockledItems)
                { // if allowed and user wants to block, remove from allowed list
                    if (allowedItems.Contains(item))
                        allowedItems.Remove(item);
                }

                foreach (var item in allowedItems)
                { // add allowed items to new items
                    var elm = xmlRss.DocumentElement.SelectSingleNode("//item/guid[. = '" + item + "']/..");
                    filteredItems.Add(elm);
                }
            }


            XmlTextWriter feedWriter = new XmlTextWriter(Response.OutputStream, Encoding.UTF8);
            feedWriter.WriteStartDocument();

            // These are RSS Tags
            feedWriter.WriteStartElement("rss");
            feedWriter.WriteAttributeString("version", "2.0");

            feedWriter.WriteStartElement("channel");
            feedWriter.WriteElementString("title", "arunes");
            feedWriter.WriteElementString("link", "http://www.arunes.com");
            feedWriter.WriteElementString("description", "arunes.com");
            feedWriter.WriteElementString("copyright", "Copyright 2012 arunes.com. All rights reserved.");

            // Write all Posts in the rss feed
            foreach (var item in filteredItems)
            {
                feedWriter.WriteStartElement("item");
                feedWriter.WriteElementString("title", item["title"].InnerText);
                feedWriter.WriteElementString("description", item["description"].InnerText);
                feedWriter.WriteElementString("link", item["link"].InnerText);
                feedWriter.WriteElementString("pubDate", item["pubDate"].InnerText);
                feedWriter.WriteElementString("guid", item["guid"].InnerText);
                feedWriter.WriteEndElement();
            }

            // Close all open tags tags
            feedWriter.WriteEndElement();
            feedWriter.WriteEndElement();
            feedWriter.WriteEndDocument();
            feedWriter.Flush();
            feedWriter.Close();

            Response.End();
        }

        private bool IsTrue(bool[] conditions, string op)
        {
            switch (op)
            {
                case "and":
                    foreach (var cond in conditions)
                        if (!cond) return false;

                    return true;

                case "or":
                    foreach (var cond in conditions)
                        if (cond) return true;

                    return false;
            }

            return true;
        }
    }
}